﻿using System;
using System.Collections.Generic;
using ParserGenerator.Collections;
using ParserGenerator.Extensions;

namespace ParserGenerator.SyntacticAnalysis
{
    [Serializable]
    public sealed class FreshNameGenerator
    {
        private int _counter;

        [NonSerialized]
        private ReadOnlySet<string> _usedNamesWrapper;
        private readonly HashSet<string> _usedNames;
        public ReadOnlySet<string> UsedNames
        {
            get
            {
                if (_usedNamesWrapper == null)
                    _usedNamesWrapper = _usedNames.AsReadOnly();
                return _usedNamesWrapper;
            }
        }

        public FreshNameGenerator()
        {
            _usedNames = new HashSet<string>();
        }

        public FreshNameGenerator(IEnumerable<string> collection)
        {
            if (collection == null)
                throw new ArgumentNullException(nameof(collection));
            _usedNames = new HashSet<string>(collection);
        }

        public void UseName(string name)
        {
            if (name == null)
                throw new ArgumentNullException(nameof(name));
            _usedNames.Add(name);
        }

        public void UseNames(IEnumerable<string> collection)
        {
            if (collection == null)
                throw new ArgumentNullException(nameof(collection));
            _usedNames.UnionWith(collection);
        }

        public string GetFreshName(string hint)
        {
            if (hint == null)
                throw new ArgumentNullException(nameof(hint));
            if (!_usedNames.Contains(hint))
                return hint;
            for (int i = 1; i <= 3; i++)
            {
                string name = hint + new string('\'', i);
                if (!_usedNames.Contains(name))
                    return name;
            }
            while (true)
            {
                _counter++;
                string name = hint + _counter;
                if (!_usedNames.Contains(name))
                    return name;
            }
        }

        public sealed override string ToString()
        {
            return string.Join("\n", _usedNames);
        }
    }
}
